package fr.upmc.aladyn.shared;

import static org.junit.Assert.*;

import java.util.HashMap;


//import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import fr.upmc.aladyn.exemples.ObjetTrans;
/**
 * Test class of our class ObjectSingleton.
 * 
 * @author Thierry Wong
 * @author Seyyid ahmed Ouir 
 */

public class ObjectSingletonTest {
	
	private ObjectSingleton objectSingleton;

	@Before
	public void setUp() throws Exception {
		objectSingleton = new ObjectSingleton();
	}

	/**
	 * Constructor test.
	 */
	@Test
	public void testObjectSingleton() {
		ObjectSingleton objectSingleton = new ObjectSingleton();
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
	}

	/**
	 * GetInstance method test
	 */
	@Test
	public void testGetInstance() {
		ObjectSingleton o1 = ObjectSingleton.getInstance();
		ObjectSingleton o2 = ObjectSingleton.getInstance();
		assertTrue(o1 == o2);
	}

	/**
	 * TransactionEnCours method test
	 */
	@Test
	public void testTransactionEnCours() {
		assertFalse(objectSingleton.transactionEnCours());
		objectSingleton.debutMethodeTrans();
		assertTrue(objectSingleton.transactionEnCours());
		objectSingleton.finMethodeTrans();
		assertFalse(objectSingleton.transactionEnCours());
	}

	/**
	 * DebutMethodeTrans method test. Two imbricated Transactionnable methods
	 * m0 and m1 are called. We verify that environments are successfully 
	 * created after method call.
	 */
	
	/*
	 * m0 {
	 *   m1 {
	 */
	@Test
	public void testDebutMethodeTrans() {
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
		
		objectSingleton.debutMethodeTrans();
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertTrue(objectSingleton.getIndexList().size() == 1);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
				
		objectSingleton.debutMethodeTrans();
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(objectSingleton.getIndexList().size() == 2);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 1);
	}

	
	/**
	 * FinMethodeTrans method test. We begin a transaction, verify environment 
	 * is initiated. After call of method, we verify that the environment has 
	 * been freed. We suppose that overall method is non Transactionable so 
	 * we end the Transaction state at the end.
	 */
	
	/*
	 * m0 {}
	 */
	@Test
	public void testFinMethodeTrans_1() {
		objectSingleton.debutMethodeTrans();

		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertTrue(objectSingleton.getIndexList().size() == 1);
		
		objectSingleton.finMethodeTrans();
		
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
	}
	
	
	/**
	 * Second test for FinMethodTrans. We imbricate two methods. We verify 
	 * that all environments are being freed.
	 */
	
	// imbriquer 2 methodes transactionables
	/*
	 * m0 {
	 * 	m1 {}
	 * }
	 */
	@Test
	public void testFinMethodeTrans_2() {
		objectSingleton.debutMethodeTrans(); // debut m0
		objectSingleton.debutMethodeTrans(); // debut m1

		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(objectSingleton.getIndexList().size() == 2);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 1);
		
		objectSingleton.finMethodeTrans(); // fin m1
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(objectSingleton.getIndexList().size() == 1);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		
		
		objectSingleton.finMethodeTrans(); // fin m0
		
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
	}
	
	/**
	 * Another extended method test for FinMethodeTrans. Scenario where 
	 * method0 calls method1 which finishes and then calls method2 which 
	 * calls respectively method3 and method4.
	 * 
	 * We verify at the the entry and of exit of methods that our environments 
	 * are coherent with determined state.
	 * 
	 * m0 {
	 *   m1 {}
	 *   m2 {
	 *     m3 {}
	 *     m4 {}
	 *   }
	 * }
	 */
	@Test
	public void testFinMethodeTrans_3() {
		objectSingleton.debutMethodeTrans(); // debut m0
		
		objectSingleton.debutMethodeTrans(); // debut m1
		objectSingleton.finMethodeTrans(); // fin m1
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(objectSingleton.getIndexList().size() == 1);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		
		objectSingleton.debutMethodeTrans(); // debut m2
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 3);
		assertTrue(objectSingleton.getIndexList().size() == 2);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 2);
		
		objectSingleton.debutMethodeTrans(); // debut m3
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		assertTrue(objectSingleton.getIndexList().size() == 3);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 2);
		assertTrue(objectSingleton.getIndexList().get(2) == 3);
		
		objectSingleton.finMethodeTrans(); // fin m3
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		assertTrue(objectSingleton.getIndexList().size() == 2);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 2);
		
		objectSingleton.debutMethodeTrans(); // debut m4
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 5);
		assertTrue(objectSingleton.getIndexList().size() == 3);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 2);
		assertTrue(objectSingleton.getIndexList().get(2) == 4);
		
		objectSingleton.finMethodeTrans(); // fin m4
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 5);
		assertTrue(objectSingleton.getIndexList().size() == 2);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		assertTrue(objectSingleton.getIndexList().get(1) == 2);
		
		objectSingleton.finMethodeTrans(); // fin m2
		
		assertTrue(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 5);
		assertTrue(objectSingleton.getIndexList().size() == 1);
		assertTrue(objectSingleton.getIndexList().get(0) == 0);
		
		objectSingleton.finMethodeTrans(); // fin m0
		
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
	}

	/*
	 * Test method for method sauvegarder. We verify that entered values in save
	 * correspond to values in the current instance. Verification of inherited 
	 * fields save from superclass also.
	 * 
	 * m0 {
	 *   o1
	 *   o2
	 * }
	 */
	
	/*
	 * Dans la methode transactionnable "m0", on modifie 2 objet 
	 * transactionnables "o1" et "o2" donc on les sauvegarde dans l'environement
	 */

	@Test
	public void testSauvegarder_1() {
		ObjetTrans o1 = new ObjetTrans("o1", 1, 101);
		ObjetTrans o2 = new ObjetTrans("o2", 2, 102);
		
		assertTrue(o1.getName().equals("o1"));
		assertTrue(o1.getValue() == 1);
		assertTrue(o1.getValueSuper() == 101);
		
		objectSingleton.debutMethodeTrans(); // debut m0 ***** debut transaction
		
		// une seule methode tansactionnable -> un seul env dans "objectSingleton"
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		// l'env de "m0" est vide car on n'a pas encore modifie un objet transactionnable
		assertTrue(objectSingleton.getEnvironnements().get(0).isEmpty());
		
		objectSingleton.sauvegarder(o1);
		
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		// l'env de "m0" n'est plus vide
		assertFalse(objectSingleton.getEnvironnements().get(0).isEmpty());
		HashMap<Object, Object> envCourant = objectSingleton.getEnvironnements().get(0);
		// l'env de "m0" ne contient que la sauvegarde de l'objet "o1"
		assertTrue(envCourant.size() == 1);
		assertTrue(envCourant.containsKey(o1));
		assertTrue(envCourant.get(o1).equals(o1));
		
		o1.setName("o1_modif");
		o1.setValue(11);
		o1.setValueSuper(1111);
		
		// recuperation de la sauvegarde de "o1" a partir de l'env
		// et verifier qu'elle n'a pas change apres la modification de "o1"
		ObjetTrans o1_copie = (ObjetTrans) envCourant.get(o1);
		assertTrue(o1_copie.getName().equals("o1"));
		assertTrue(o1_copie.getValue() == 1);
		assertTrue(o1_copie.getValueSuper() == 101);
		
		objectSingleton.sauvegarder(o2);
		
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertFalse(objectSingleton.getEnvironnements().get(0).isEmpty());
		assertTrue(envCourant.size() == 2);
		assertTrue(envCourant.containsKey(o1));
		assertTrue(envCourant.containsKey(o2));
		
		objectSingleton.sauvegarder(o1);
		
		// "o1" est deja present dans l'env, on ne va pas le sauvegarder de nouveau
		assertTrue(envCourant.size() == 2);
		assertTrue(envCourant.containsKey(o1));
		assertTrue(envCourant.containsKey(o2));
		
		o1_copie = (ObjetTrans) envCourant.get(o1);
		assertTrue(o1_copie.getName().equals("o1"));
		assertTrue(o1_copie.getValue() == 1);
		assertTrue(o1_copie.getValueSuper() == 101);
		
		objectSingleton.finMethodeTrans(); // fin m0 ***** fin de la transaction
		
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
	}

	/*
	 * soient les methodes transactionnables m0, m1, m2
	 * et les objets transactionnables o1, o2, o3
	 * 
	 * 				// envs []  => pas de transaction en cours
	 * 
	 * m0 {			// envs [ env0[] ]  => debut transaction
	 *   o1			// envs [ env0[o1] ]
	 *   o2			// envs [ env0[o1, o2] ]
	 *   m1 {		// envs [ env0[o1, o2] env1[] ]
	 *     o3		// envs [ env0[o1, o2] env1[o3] ]
	 *   }			// envs [ env0[o1, o2] env1[o3] ]
	 * }			// envs []  => fin de la transaction
	 * 
	 * m2 {			// envs [ env0[] ]  => debut transaction
	 *   o3			// envs [ env0[o3] ]
	 * }			// envs []  => fin de la transaction
	 */
	@Test
	public void testSauvegarder_2() {
		ObjetTrans o1 = new ObjetTrans("o1", 1, 101);
		ObjetTrans o2 = new ObjetTrans("o2", 2, 102);
		ObjetTrans o3 = new ObjetTrans("o3", 3, 103);
		
		objectSingleton.debutMethodeTrans(); // debut m0 ***** => debut transaction
		
		objectSingleton.sauvegarder(o1);
		o1.setName("o1_modif");
		o1.setValue(11);
		
		objectSingleton.sauvegarder(o2);
		o2.setName("o2_modif");
		o2.setValue(22);
		
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertFalse(objectSingleton.getEnvironnements().get(0).isEmpty());
		HashMap<Object, Object> envM0 = objectSingleton.getEnvironnements().get(0);
		assertTrue(envM0.size() == 2);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM0.containsKey(o2));
		
		objectSingleton.debutMethodeTrans(); // debut m1
		
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(objectSingleton.getEnvironnements().get(1).isEmpty());
		
		objectSingleton.sauvegarder(o3);
		o3.setName("o3_modif");
		o3.setValue(33);
		
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(envM0.size() == 2);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM0.containsKey(o2));
		assertFalse(objectSingleton.getEnvironnements().get(1).isEmpty());
		HashMap<Object, Object> envM1 = objectSingleton.getEnvironnements().get(1);
		assertTrue(envM1.size() == 1);
		assertTrue(envM1.containsKey(o3));
		
		objectSingleton.finMethodeTrans(); // fin m1
		
		objectSingleton.sauvegarder(o3);
		
		// "o3" est deja present dans l'env, on ne va pas le sauvegarder de nouveau
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		assertTrue(envM0.size() == 2);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM0.containsKey(o2));
		assertFalse(objectSingleton.getEnvironnements().get(1).isEmpty());
		assertTrue(envM1.size() == 1);
		assertTrue(envM1.containsKey(o3));
		
		objectSingleton.finMethodeTrans(); // fin m0 ***** => fin de la transaction
		
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		
		objectSingleton.debutMethodeTrans(); // debut m2 ***** => debut transaction
		
		objectSingleton.sauvegarder(o3);
		
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertFalse(objectSingleton.getEnvironnements().get(0).isEmpty());
		HashMap<Object, Object> envM2 = objectSingleton.getEnvironnements().get(0);
		assertTrue(envM2.size() == 1);
		assertTrue(envM2.containsKey(o3));
	}
	
	/*
	 * m0 {				// envs [ env0[] ]  => debut transaction
	 *   o1				// envs [ env0[o1] ]
	 *   o2				// envs [ env0[o1, o2] ]
	 *   
	 *   try {
	 *     <*> exception
	 *   } catch () {
	 *     => restaurer // => envs [ env0[] ] ("o1" et "o2" restaures)
	 *   }
	 *   
	 *   o3				// envs [ env0[o3] ]
	 *   o1				// envs [ env0[o3, o1] ]
	 * }
	 */
	@Test
	public void testRestaurer_1() {
		ObjetTrans o1 = new ObjetTrans("o1", 1, 101);
		ObjetTrans o2 = new ObjetTrans("o2", 2, 102);
		ObjetTrans o3 = new ObjetTrans("o3", 2, 102);
		
		objectSingleton.debutMethodeTrans(); // debut m0 ***** => debut transaction
		
		// sauvegarde de "o1" et de "o2"
		objectSingleton.sauvegarder(o1);
		objectSingleton.sauvegarder(o2);
		
		// modification de "o1" et de "o2"
		o1.setName("o1_modif");
		o1.setValue(11);
		o1.setValueSuper(1111);
		o2.setName("o2_modif");
		o2.setValue(22);
		o2.setValueSuper(2222);
		
		// avant la restauration
		assertTrue(o1.getName().equals("o1_modif") && o1.getValue() == 11 && o1.getValueSuper() == 1111);
		assertTrue(o2.getName().equals("o2_modif") && o2.getValue() == 22 && o2.getValueSuper() == 2222);
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		HashMap<Object, Object> envCourant = objectSingleton.getEnvironnements().get(0);
		assertTrue(envCourant.size() == 2);
		assertTrue(envCourant.containsKey(o1));
		assertTrue(envCourant.containsKey(o2));
		
		// <*> simulation d'une exception
		
		objectSingleton.restaurer();

		// apres la restauration
		assertTrue(o1.getName().equals("o1") && o1.getValue() == 1 && o1.getValueSuper() == 101);
		assertTrue(o2.getName().equals("o2") && o2.getValue() == 2 && o2.getValueSuper() == 102);
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertTrue(envCourant.size() == 0);
		
		objectSingleton.sauvegarder(o3);
		objectSingleton.sauvegarder(o1);
		
		assertTrue(envCourant.size() == 2);
		assertTrue(envCourant.containsKey(o3));
		assertTrue(envCourant.containsKey(o1));
		

	}
	
	/*
	 * objets transactionnables : o1, o2, o3, ...
	 * notation : modification de o1 => o1*
	 *            modification de o1* => o1**
	 * 
	 * m0 {
	 *   o1*
	 *   m1 { o2*, o3* }
	 *   m2 {
	 *     o4*, o1**
	 *     m3 { o5*, o6*, <* exception1 *>, o7* }
	 *     o8*
	 *     <* exception2 *>
	 *     m4 { o9* }
	 *     o10*
	 *   }
	 * }
	 * 
	 * detail :
	 * 
	 * m0 {
	 *   o1*
	 *   
	 *   m1 {
	 *     o2*
	 *     o3*
	 *   }
	 *   
	 *   m2 {
	 *     o4*
	 *     o1**
	 *     
	 *     m3 {
	 *       o5*
	 *       o6*
	 *       
	 *       // envs [ env0[o1] env1[o2, o3] env2[o4, o1*] env3[o5, o6] ]
	 *       
	 *       try {
	 *         <*> exception1
	 *       } catch () {
	 *         => restauration de : "o5" et "o6" 
	 *       }
	 *       
	 *       // envs [ env0[o1] env1[o2, o3] env2[o4, o1*] env3[] ]
	 *       
	 *       o7*
	 *     }
	 *     
	 *     
	 *     o8*
	 *     
	 *     // envs [ env0[o1] env1[o2, o3] env2[o4, o1*, o8] env3[o7] ]
	 *     
	 *     try {
	 *       <*> exception2
	 *     } catch () {
	 *       => restauration de : "o7", "o1*", "o8"
	 *     }
	 *     
	 *     // envs [ env0[o1] env1[o2, o3] env2[] ]
	 *     
	 *     m4 {
	 *       o9*
	 *     }
	 *     
	 *     o10*
	 *     
	 *     // envs [ env0[o1] env1[o2, o3] env2[o10] env4[o9] ]
	 *   }
	 * }  // envs [ ]
	 */
	@Test
	public void testRestaurer_2() {
		ObjetTrans o1 = new ObjetTrans("o1", 1, 101);
		ObjetTrans o2 = new ObjetTrans("o2", 2, 102);
		ObjetTrans o3 = new ObjetTrans("o3", 3, 103);
		ObjetTrans o4 = new ObjetTrans("o4", 4, 104);
		ObjetTrans o5 = new ObjetTrans("o5", 5, 105);
		ObjetTrans o6 = new ObjetTrans("o6", 6, 106);
		ObjetTrans o7 = new ObjetTrans("o7", 7, 107);
		ObjetTrans o8 = new ObjetTrans("o8", 8, 108);
		ObjetTrans o9 = new ObjetTrans("o9", 9, 109);
		ObjetTrans o10 = new ObjetTrans("o10", 10, 110);
		
		objectSingleton.debutMethodeTrans(); // debut m0 ***** => debut transaction
		
		// sauvegarde de "o1", puis une modification
		objectSingleton.sauvegarder(o1);
		o1.setName("o1_modif*1*");
		
		objectSingleton.debutMethodeTrans(); // debut m1
		
		// sauvegarde de : "o2", "o3"
		objectSingleton.sauvegarder(o2);
		objectSingleton.sauvegarder(o3);
		o2.setName("o2_modif");
		o3.setName("o3_modif");
		
		objectSingleton.finMethodeTrans(); // fin m1
		
		objectSingleton.debutMethodeTrans(); // debut m2

		// sauvegarde de : "o4", "o1*"
		objectSingleton.sauvegarder(o4);
		objectSingleton.sauvegarder(o1);
		o4.setName("o4_modif");
		o1.setName("o1_modif*2*");

		objectSingleton.debutMethodeTrans(); // debut m3

		// sauvegarde de : "o5", "o6"
		objectSingleton.sauvegarder(o5);
		objectSingleton.sauvegarder(o6);
		o5.setName("o5_modif");
		o6.setName("o6_modif");
		
		// avant la restauration (exception 1)
		assertTrue(o1.getName().equals("o1_modif*2*"));
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(o4.getName().equals("o4_modif"));
		assertTrue(o5.getName().equals("o5_modif"));
		assertTrue(o6.getName().equals("o6_modif"));
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		HashMap<Object, Object> envM0 = objectSingleton.getEnvironnements().get(0);
		HashMap<Object, Object> envM1 = objectSingleton.getEnvironnements().get(1);
		HashMap<Object, Object> envM2 = objectSingleton.getEnvironnements().get(2);
		HashMap<Object, Object> envM3 = objectSingleton.getEnvironnements().get(3);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		assertTrue(envM2.size() == 2);
		assertTrue(envM2.containsKey(o4));
		assertTrue(envM2.containsKey(o1));
		assertTrue(envM3.size() == 2);
		assertTrue(envM3.containsKey(o5));
		assertTrue(envM3.containsKey(o6));
		// envs [ env0[o1] env1[o2, o3] env2[o4, o1*] env3[o5, o6] ]
		
		// <*> simulation de l'exception 1 (dans la methode m3)
		
		objectSingleton.restaurer();

		// apres la restauration (exception 1)
		// envs [ env0[o1] env1[o2, o3] env2[o4, o1*] env3[] ]
		assertTrue(o1.getName().equals("o1_modif*2*"));
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(o4.getName().equals("o4_modif"));
		assertTrue(o5.getName().equals("o5"));
		assertTrue(o6.getName().equals("o6"));
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		assertTrue(envM2.size() == 2);
		assertTrue(envM2.containsKey(o4));
		assertTrue(envM2.containsKey(o1));
		assertTrue(envM3.size() == 0);

		// sauvegarde de : "o7"
		objectSingleton.sauvegarder(o7);
		o7.setName("o7_modif");
		
		objectSingleton.finMethodeTrans(); // fin m3
		
		// sauvegarde de : "o8"
		objectSingleton.sauvegarder(o8);
		o8.setName("o8_modif");
		
		// avant la restauration (exception 2)
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(o4.getName().equals("o4_modif"));
		assertTrue(o1.getName().equals("o1_modif*2*"));
		assertTrue(o5.getName().equals("o5"));
		assertTrue(o6.getName().equals("o6"));
		assertTrue(o7.getName().equals("o7_modif"));
		assertTrue(o8.getName().equals("o8_modif"));
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		assertTrue(envM2.size() == 3);
		assertTrue(envM2.containsKey(o4));
		assertTrue(envM2.containsKey(o1));
		assertTrue(envM2.containsKey(o8));
		assertTrue(envM3.size() == 1);
		assertTrue(envM3.containsKey(o7));
		// envs [ env0[o1] env1[o2, o3] env2[o4, o1*, o8] env3[o7] ]
		
		// <*> simulation de l'exception 2 (dans la methode m2)
		
		objectSingleton.restaurer();
		
		// apres la restauration (exception 2)
		// envs [ env0[o1] env1[o2, o3] env2[] ]
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(o4.getName().equals("o4"));
		assertTrue(o1.getName().equals("o1_modif*1*"));
		assertTrue(o5.getName().equals("o5"));
		assertTrue(o6.getName().equals("o6"));
		assertTrue(o7.getName().equals("o7"));
		assertTrue(o8.getName().equals("o8"));
		assertTrue(objectSingleton.getEnvironnements().size() == 3);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		assertTrue(envM2.size() == 0);

		
		objectSingleton.debutMethodeTrans(); // debut m4
		
		// sauvegarde de : "o9"
		objectSingleton.sauvegarder(o9);
		o9.setName("o9_modif");
		
		objectSingleton.finMethodeTrans(); // fin m4
		
		// sauvegarde de : "o10"
		objectSingleton.sauvegarder(o10);
		o10.setName("o10_modif");
		
		objectSingleton.finMethodeTrans(); // fin m2
		
		// envs [ env0[o1] env1[o2, o3] env2[o10] env4[o9] ]
		assertTrue(o1.getName().equals("o1_modif*1*"));
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(o4.getName().equals("o4"));
		assertTrue(o5.getName().equals("o5"));
		assertTrue(o6.getName().equals("o6"));
		assertTrue(o7.getName().equals("o7"));
		assertTrue(o8.getName().equals("o8"));
		assertTrue(o9.getName().equals("o9_modif"));
		assertTrue(o10.getName().equals("o10_modif"));
		assertTrue(objectSingleton.getEnvironnements().size() == 4);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		assertTrue(envM2.size() == 1);
		assertTrue(envM2.containsKey(o10));
		HashMap<Object, Object> envM4 = objectSingleton.getEnvironnements().get(3);
		assertTrue(envM4.containsKey(o9));
		
		objectSingleton.finMethodeTrans(); // fin m0 ***** fin de la transaction
		
		// envs [ ]
		assertFalse(objectSingleton.transactionEnCours());
		assertTrue(objectSingleton.getEnvironnements().size() == 0);
		assertTrue(objectSingleton.getIndexList().size() == 0);
	}
	
	/*
	 * m0 {
	 *   o1
	 *   try {
	 *     m1 {
	 *       o2
	 *       o3
	 *       <*> exception (sans catch)
	 *       => restaure : o2, o3
	 *       => throw
	 *   } catch () {
	 *     restaure : o1
	 *   }
	 * }
	 */
	@Test
	public void testRestaurerCatchFinal() {
		ObjetTrans o1 = new ObjetTrans("o1", 1, 101);
		ObjetTrans o2 = new ObjetTrans("o2", 2, 102);
		ObjetTrans o3 = new ObjetTrans("o3", 3, 103);
		
		objectSingleton.debutMethodeTrans(); // debut m0 ***** => debut transaction
		
		// sauvegarde de "o1", puis une modification
		objectSingleton.sauvegarder(o1);
		o1.setName("o1_modif");
		
		objectSingleton.debutMethodeTrans(); // debut m1
		
		// sauvegarde de : "o2", "o3"
		objectSingleton.sauvegarder(o2);
		objectSingleton.sauvegarder(o3);
		o2.setName("o2_modif");
		o3.setName("o3_modif");
		
		// avant la restauration (exception 1)
		assertTrue(o1.getName().equals("o1_modif"));
		assertTrue(o2.getName().equals("o2_modif"));
		assertTrue(o3.getName().equals("o3_modif"));
		assertTrue(objectSingleton.getEnvironnements().size() == 2);
		HashMap<Object, Object> envM0 = objectSingleton.getEnvironnements().get(0);
		HashMap<Object, Object> envM1 = objectSingleton.getEnvironnements().get(1);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 2);
		assertTrue(envM1.containsKey(o2));
		assertTrue(envM1.containsKey(o3));
		// envs [ env0[o1] env1[o2, o3] ]
		
		// <*> simulation de l'exception (sans clause catch)
		
		objectSingleton.restaurerCatchFinal();
		
		// apres la restauration (exception 1)
		// envs [ env0[o1] ]
		assertTrue(o1.getName().equals("o1_modif"));
		assertTrue(o2.getName().equals("o2"));
		assertTrue(o3.getName().equals("o3"));
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertTrue(envM0.size() == 1);
		assertTrue(envM0.containsKey(o1));
		assertTrue(envM1.size() == 0);
		
		objectSingleton.restaurer();
		
		assertTrue(objectSingleton.getEnvironnements().size() == 1);
		assertTrue(envM0.size() == 0);
		
		objectSingleton.finMethodeTrans(); // fin m0 ***** fin de la transaction
	}

}
